﻿using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;

namespace Seagull.Model
{
    [DebuggerDisplay("{ToString()}")]
    public struct Frame : IEquatable<Frame>
    {
        public const int FrameSize = 219;
        public const short DataLength = 200;

        public const byte Head = 0x7E;
        public const byte HeadLength = 1;

        public const byte Tail = 0x0D;
        public const byte TailLength = 1;

        private static readonly ReadOnlyCollection<byte> _emptyData = new ReadOnlyCollection<byte>(new byte[DataLength]);

        public Frame(DateTime timestamp, byte[] data = null)
        {
            _timestamp = timestamp;
            _data = data ?? _emptyData.ToArray();
            _channel = Model.Channel.UnknownChannel;
        }

        public Frame(byte channel, DateTime timestamp, byte[] data)
            : this()
        {
            _channel = channel;
            _timestamp = timestamp;
            _data = data;
        }

        private byte _channel;

        public byte Channel
        {
            get { return _channel; }
            set { _channel = value; }
        }


        private DateTime _timestamp;
        public DateTime Timestamp
        {
            get { return _timestamp; }
            set { _timestamp = value; }
        }

        private byte[] _data;
        public byte[] Data
        {
            get { return _data; }
            set { _data = value; }
        }

        #region Equality Members

        public bool Equals(Frame other)
        {
            return other._timestamp.Equals(_timestamp) && Equals(other._data, _data);
        }

        public override bool Equals(object obj)
        {
            if(ReferenceEquals(null, obj))
                return false;
            if(obj.GetType() != typeof(Frame))
                return false;
            return Equals((Frame)obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (_timestamp.GetHashCode() * 397) ^ (_data != null ? _data.GetHashCode() : 0);
            }
        }

        public static bool operator ==(Frame left, Frame right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Frame left, Frame right)
        {
            return !left.Equals(right);
        }

        #endregion

        public override string ToString()
        {
            return string.Format(
                "Timestamp: {0:yyyy/MM/dd HH:mm:ss.fff}, Channel: {1}, Empty: {2}", 
                _timestamp, _channel, _data.All(t => t == 0));
        }

        public static bool IsValidFrameType(byte frameType)
        {
            return frameType == 0x11 || frameType == 0x22;
        }
    }
}
